<template>
  <div id="x6-container-id" ref="x6Container" class="x6-container">
    <!-- 图渲染 DOM -->
    <div id="field-data-lineage-x6-canvas" class="data-lineage-pipeline"></div>

    <!-- toolbar -->
    <tool-bar
      style="position: absolute; right: 20px; top: 20px;"
      @action="toolBarHandler"
    />
  </div>
</template>

<script lang="ts">
/**
 * 数据血缘 字段级血缘 pipeline
 */
import { Component, Ref, Vue } from 'vue-property-decorator'
import LineageGraph from '@/components/x6-data-lineage'
import DataLineage from '@/store/modules/data-lineage'
import ToolBar from '@/components/tool-bar'

let lineageGraphInstance: any = null

@Component({
  name: 'FieldLineagePipeline',
  components: {
    ToolBar,
  },
})
export default class FieldLineagePipeline extends Vue {
  $eventBus: any
  @Ref('x6Container') readonly x6Container!: any
  private graph: any = null // X6 画布实例
  // TODO 菜单
  private contextmenuVisible: boolean = false // 节点/边 菜单显示
  private menuPosition: { x: number; y: number } = { x: -1000, y: -1000 } // 菜单位置
  private contextMenuEdgeData: any = null // 当前菜单边

  private mounted() {
    if (lineageGraphInstance) {
      this.destroyGraph()
    }

    this.$nextTick(() => {
      this.init()
      this.addCanvasCustomNodeListener()
      this.renderLineage()
    })

    this.$eventBus.$on('analytic-success', () => {
      if (!lineageGraphInstance) {
        this.init()
      }
      lineageGraphInstance.clearGraphData()
      this.renderLineage()
    })

    this.$eventBus.$on('clear-graph', () => {
      if (lineageGraphInstance) {
        lineageGraphInstance.clearGraphData()
      }
    })

    this.$once('hook:beforeDestroy', () => {
      this.destroyGraph()
    })
  }

  private destroyGraph() {
    lineageGraphInstance.dispose()
    lineageGraphInstance = null
  }

  private init() {
    const width: number = this.x6Container.offsetWidth
    const height: number = this.x6Container.offsetHeight
    const container: any = document.querySelector(
      '#field-data-lineage-x6-canvas'
    )
    lineageGraphInstance = new LineageGraph({
      width,
      height,
      container,
      plugins: ['snapline'],
      nodeType: 'FIELD',
    })
    this.graph = lineageGraphInstance.graph

    this.graph.on('edge:mouseenter', ({ edge }: any) => {
      lineageGraphInstance.hoverEdge(edge)
    })

    this.graph.on('edge:mouseleave', ({ edge }: any) => {
      lineageGraphInstance.hoverLeaveEdge(edge)
    })

    // TODO 边的菜单 边的 label 事件
    this.graph.on('edge:detail', ({ e, edge }: any) => {
      e.stopPropagation()
      this.contextMenuEdgeData = edge.data
      const containerBodyInfo: any = this.x6Container.getBoundingClientRect()
      this.menuPosition.x = e.clientX - containerBodyInfo.x
      this.menuPosition.y = e.clientY - containerBodyInfo.y
      this.contextmenuVisible = true
    })

    // TODO 边的 mouseenter 事件（contextmenu， click）
    this.graph.on('edge:click', ({ e, edge }: any) => {
      this.contextMenuEdgeData = edge.data
      const containerBodyInfo: any = this.x6Container.getBoundingClientRect()
      this.menuPosition.x = e.clientX - containerBodyInfo.x
      this.menuPosition.y = e.clientY - containerBodyInfo.y
      this.contextmenuVisible = true
      lineageGraphInstance.selectEdge(edge)
    })

    this.graph.on('blank:click', () => {
      this.contextmenuVisible = false
    })

    this.graph.on('blank:dblclick', () => {
      lineageGraphInstance.toggleSelectedNode({ nodeId: '', fieldName: '' })
      lineageGraphInstance.selectEdge(null)
    })

    this.graph.on('blank:mousedown', () => {
      this.contextmenuVisible = false
    })

    this.graph.on('blank:contextmenu', () => {
      this.contextmenuVisible = false
    })
    this.graph.on('scale', () => {
      this.contextmenuVisible = false
    })
    this.graph.on('resize', () => {
      this.contextmenuVisible = false
    })
    // panning
    this.graph.on('translate', () => {
      this.contextmenuVisible = false
    })
  }

  /**
   * 初始获取主表及上下游血缘表节点
   * @private
   */
  private renderLineage() {
    const { fieldNodeInfoList = [], fieldEdgeInfoList = [] } =
      DataLineage.fieldDataLineage || {}
    if (fieldNodeInfoList && fieldNodeInfoList.length > 0) {
      lineageGraphInstance.renderGraph(
        fieldNodeInfoList,
        fieldEdgeInfoList,
        true
      )
    }
  }

  /**
   * 事件总线监听自定义Vue节点事件
   * @private
   */
  private addCanvasCustomNodeListener() {
    this.$eventBus.$on(
      'field-data-lineage-custom-vue-node-event',
      ({ fieldName, tableName, eventType, databaseName }: any) => {
        switch (eventType) {
          case 'field-mouseenter': {
            lineageGraphInstance.hoverNode({
              nodeId: `${databaseName}_${tableName}`,
              fieldName,
            })
            break
          }
          case 'field-mouseleave': {
            lineageGraphInstance.clearOnHoverHighlightLinkStates()
            lineageGraphInstance.paintEdges()
            break
          }
          case 'field-toggle-select': {
            lineageGraphInstance.toggleSelectedNode({
              nodeId: `${databaseName}_${tableName}`,
              fieldName,
            })
            break
          }
          default:
            break
        }
      }
    )
  }

  private toolBarHandler(tool: any) {
    this.contextmenuVisible = false
    const { key } = tool
    switch (key) {
      case 'ZOOM_IN': {
        this.graph.zoom(0.1)
        break
      }
      case 'ZOOM_OUT': {
        this.graph.zoom(-0.1)
        break
      }
      case 'FIT_VIEW': {
        this.graph?.scaleContentToFit({
          padding: 20,
        })
        this.graph?.centerContent({
          padding: 20,
        })
        break
      }
      case 'FIT_CENTER': {
        this.graph?.centerContent({
          padding: 20,
        })
        break
      }
      case 'INIT': {
        lineageGraphInstance?.recoverRenderGraph()
        break
      }
      default:
        break
    }
  }
}
</script>

<style lang="less" scoped>
.x6-container {
  height: 100%;
  position: relative;
  width: 100%;

  .data-lineage-pipeline {
    background: #fff;
    height: 100%;
    position: relative;
    width: 100%;

    .x6-graph-scroller .x6-graph-scroller-paged .x6-graph {
      box-shadow: none;
    }
  }
}
</style>
